/*
a Herwin production '98
version 1.0
by Herwin harSens van Welbergen 
chloorrubberharsens@yahoo.com
http://home.student.utwente.nl/h.vanwelbergen/
*/

#ifndef adlib
#define adlib
#include <conio.h>
#include <iostream.h>
//Well my Soundblaster compatible just uses left an right as both, but
//maybe it works on yours
static enum speaker{both=0x388,left=0x220,right=0x222};
//----------------------------------------------------------------------
void wait(int i)
{	for (int n=0;n<i;n++)
		inp(both);
}
//-----------------------------------------------------------------------
int op_channel(int channel,int op)
{	if (op==2)
		{	channel=(channel/3)*5+channel+3;
		}
	else channel=(channel/3)*5+channel;
	return channel;
}
//----------------------------------------------------------------------
void write(speaker i,int regist,int value)
{	outp(i,regist);
	wait(6);
	outp(i+1,value);
	wait(35);
}
//-----------------------------------------------------------------------
int Adlib_detect()
{   // test adlib compatible board, 1=ok,0=fout
	write(both,0x04,0x60);
	write(both,0x04,0x80);
	int n=inp(both);
	write(both,0x02,0xFF);
	write(both,0x04,0x21);
	wait(80);
	int n2=inp(both);
	write(both,0x04,0x60);
	write(both,0x04,0x80);
	if ((n&0xE0)==0x00)
		if((n2&0xE0)==0xC0)
			return 1;
	return 0;
}
//-----------------------------------------------------------------------
void sound(speaker i,int channel,int freq,int octave=4,int key=1)
// freq can be 0-1023
// channel can be 0-8;
// octave can be 0-7
// key=1 :channel on
// key=0: channel off
{	int msbf=freq>>8;
	int lsbf=freq-(msbf<<8);
	write(i,0xA0+channel,lsbf);
	octave<<=2;
	key<<=5;
	int n=msbf|key|octave;
	write(i,0xB0+channel,n);
}
//-----------------------------------------------------------------------
void volume(speaker i,int channel,int level,int scaling=0,int op=2)
// channel  0-8
// level    0-63
// scaling:
//	0=no change
//	1=1.5dB/8ve
//	2=3.0dB/8ve
//	3=6.0dB/8ve
// scaling verhoogt volume met x dB als frequency stijgt
{   level=63-level;// huh
	scaling<<=6;
	channel=op_channel(channel,op);
	int n=scaling|level;
	if (n>255)
	write(i,0x40+channel,n);
}
//-----------------------------------------------------------------------
void all_volume(speaker i,int level,int scaling=0)
{   // zie boven
	for (int n=0;n<22;n++)
		volume(i,n,level,scaling);
}
//-----------------------------------------------------------------------
void attack_decay_rate(speaker i,int channel,int attack,int decay,int op=2)
{	//attack:0-15
	//decay:0-15
	// channel:0-8
	attack<<=4;
	channel=op_channel(channel,op);
	int n=attack|decay;
	write(i,0x60+channel,n);
}
//-------------------------------------------------------------------------
void shutdown(speaker i,int channel)
{	sound(i,channel,0,0,0);
}
//-------------------------------------------------------------------------
void sustain_release(speaker i,int channel,int sus,int rel,int op=2)
{	//sustain:0-15 15 is softest
	//release:0-15 15 is fastest 0=niet
	// channel:0-8
	sus<<=4;
	channel=op_channel(channel,op);
	int n=sus|rel;
	write(i,0x80+channel,n);
}
//--------------------------------------------------------------------------
void feedback(speaker i,int channel,int feedback,int alg=0)
{   //channel=0-8
	//feedback=1-7
	//alg: 0=op1 modulates op2
	//	   1=both op's produce sound directly
	feedback<<=1;
	int n=feedback|alg;
	write(i,0xC0+channel,n);
}
//--------------------------------------------------------------------------
void multiple(speaker i,int channel,int multi,int ampmod=1,int vib=1,
	int eg=0,int ksr=0,int op=2)
/* 	channel can be 0-7
	multi can be 0-15
	ampmod: 1=on
			0=off
	vib:1=on
		0=off
	eg: 1=voice is maintained until release
		0=voice begins to decay after sustain
	ksr: 1=the sound envelop is forshortened ad it rises in pitch
*/
{	ampmod<<=7;
	vib<<=6;
	eg<<=5;
	ksr<<=4;
	int n=ampmod|vib|eg|ksr|multi;
	channel=op_channel(channel,op);
	write(i,0x20+channel,n);
}
//--------------------------------------------------------------------------
void options(speaker i,int amdept=0,int vibdep=0,int rhy_ena=0,int bass_drum=0,
int snare_drum=0,int tom_tom=0,int cymbal=0,int hihat=0)
//if this works on your PC you're lucky, it doesn't work on mine and all the
//other I had tried.
{	amdept<<=7;
	vibdep<<=6;
	rhy_ena<<=5;
	bass_drum<<=4;
	snare_drum<<=3;
	tom_tom<<=2;
	cymbal<<=1;
	int n=amdept|vibdep|rhy_ena|bass_drum|tom_tom|cymbal|hihat;
	write(i,0xBD,n);
}
//--------------------------------------------------------------------------
void reset()
{   for(int n=0x1;n<0xF5;n++)
	// zet alle registers op 0, lomp maar effectief!
	{   write(both,n,0);
		write(left,n,0);
		write(right,n,0);
	}
}
#endif
